package org.netty.framework.tcpserver.handle;

import org.netty.framework.tcpserver.codec.TcpServerCodec;

import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
import io.netty.channel.socket.SocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;

/**
 * 定义pipeline,将worker线程处理的channelhandle放到责任链中.
 * （1）通过FixedLengthFrameDecoder定长解码器来解决定长消息的黏包问题；
 * （2）通过LineBasedFrameDecoder和StringDecoder来解决以回车换行符作为消息结束符的TCP黏包的问题；
 * （3）通过DelimiterBasedFrameDecoder 特殊分隔符解码器来解决以特殊符号作为消息结束符的TCP黏包问题；
 * （4）最后一种，通过LengthFieldBasedFrameDecoder 自定义长度解码器解决TCP黏包问题。 
 *  maxFrameLength 解码时,处理每个帧数据的最大长度 
 *  lengthFieldOffset 该帧数据中,存放该帧数据的长度的数据的起始位置 
 *  lengthFieldLength 记录该帧数据长度的字段本身的长度 
 *  lengthAdjustment 修改帧数据长度字段中定义的值,可以为负数 
 *  initialBytesToStrip 解析的时候需要跳过的字节数 
 *  failFast 为true,当frame长度超过maxFrameLength时立即报TooLongFrameException异常,为false,读取完整个帧再报异常
 * 
 * @author chenfanglin
 * @date 2018年9月27日下午6:11:11
 */
public class TcpServerInitializer extends ChannelInitializer<SocketChannel> {

	private Class<?> clazz;
	
	public TcpServerInitializer() {}
	
	public TcpServerInitializer(Class<?> clazz) {
		this.clazz = clazz;
	}
	
	@Override
	protected void initChannel(SocketChannel ch) throws Exception {
		ChannelPipeline pipeline = ch.pipeline();
		/**
		 * 自定义长度解码器,设置每个数据包最大长度为1024, 消息的第一个字段是长度字段,占用4个字节
		 * 可以根据自定义长度读取到一个完整的数据包
		 */
		pipeline.addLast(new LengthFieldBasedFrameDecoder(1024, 0, 4));
		/**
		 * 对客户端的请求数据包解码,返回给客户端的数据包编码
		 */
		pipeline.addLast(new TcpServerCodec(clazz));
		/**
		 * 自定义处理数据包的handle
		 */
		pipeline.addLast(new TcpChannelHandle());
	}

}
